#include "StdAfx.h"
#include "CursorIcon.h"

#include "JClass.h"

#include "backstage_runtime_KeelRuntimeWindowsImpl.h"

CCursorIcon g_cursorIcon;

CCursorIcon::CCursorIcon(void)
:m_hWnd(NULL)
,m_hIcon(NULL)
,m_hCursor(NULL)
,m_bCursorHide(FALSE)
,m_bCursorHideLast(FALSE)
{
}

CCursorIcon::~CCursorIcon(void)
{
}

HBITMAP CCursorIcon::CreateDIBitmapFromBuf( HWND hWnd,DWORD* src,int widths,int widthd,int height )
{
	if(hWnd==NULL)
		hWnd=GetDesktopWindow();

	HDC hdc=GetDC(hWnd);
	if(hdc==NULL)
		return NULL;

	BYTE tmp[1024+sizeof(BITMAPINFOHEADER)]={0};
	BITMAPINFO *bmi=reinterpret_cast<BITMAPINFO *>(tmp);
	bmi->bmiHeader.biWidth=widthd;
	bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
	bmi->bmiHeader.biHeight = -height;
	bmi->bmiHeader.biPlanes = 1;
	bmi->bmiHeader.biBitCount = 24;
	bmi->bmiHeader.biCompression = 0;
	BYTE *pjBits=NULL;
	HBITMAP dib=CreateDIBSection(hdc,bmi, 0, (void**)&pjBits, 0, 0);

	HBITMAP ret=NULL;
	if(pjBits)
	{
		DWORD *s=src;
		int stride=(widthd*3+3)&~3;
		for(int y=0;y<height;++y)
		{
			BYTE *d=pjBits+y*stride;
			for(int x=0;x<widths;++x,++s,d+=3)
			{
				d[0]=(BYTE)(*s);
				d[1]=(BYTE)((*s)>>8);
				d[2]=(BYTE)((*s)>>16);
			}
		}

		ret=CreateDIBitmap(hdc,&bmi->bmiHeader,CBM_INIT,pjBits,bmi,0);
		GdiFlush();
	}
	DeleteObject(dib);
	ReleaseDC(hWnd,hdc);
	return ret;
}

HICON CCursorIcon::createIcon( JNIEnv *env,HWND hWnd,jintArray color,jbyteArray mask,int widths,int widthd,int height,bool isCursor ,int x,int y)
{
	HICON hIcon=NULL;

	if(color)
	{
		HBITMAP hMask=NULL;
		if(mask)
		{
			void* pMask=env->GetPrimitiveArrayCritical(mask,NULL);
			if(pMask)
			{
				hMask=CreateBitmap(widthd,height,1,1,pMask);
				GdiFlush();
				env->ReleasePrimitiveArrayCritical(mask,pMask,0);
			}
		}
		else
		{
			BYTE *pMask=new BYTE[(widthd*height+7)/8];
			memset(pMask,0,(widthd*height+7)/8);
			hMask=CreateBitmap(widthd,height,1,1,pMask);
			GdiFlush();
			delete[] pMask;
		}

		HBITMAP hColor=NULL;
		DWORD* pColor=(DWORD*)env->GetPrimitiveArrayCritical(color,NULL);
		if(pColor)
		{
			hColor=CreateDIBitmapFromBuf(hWnd,pColor,widths,widthd,height);
			env->ReleasePrimitiveArrayCritical(color,pColor,0);
		}

		if(hMask && hColor)
		{
			ICONINFO  piconinfo={0};
			piconinfo.xHotspot = x;
			piconinfo.yHotspot = y;
			piconinfo.hbmMask = hMask;
			piconinfo.hbmColor = hColor;
			piconinfo.fIcon = isCursor?FALSE:TRUE;
			hIcon = CreateIconIndirect(&piconinfo);
		}

		if(hMask)
			DeleteObject(hMask);
		if(hColor)
			DeleteObject(hColor);
	}
	return hIcon;
}

void CCursorIcon::setIconImageFromIntRasterData( JNIEnv*env,jintArray color, jbyteArray mask, jint widths, jint widthd, jint height )
{
	if(m_hWnd && IsIconic(m_hWnd))
		InvalidateRect(m_hWnd,NULL,TRUE);
	if(m_hIcon)
	{
		DestroyIcon(m_hIcon);
		m_hIcon=NULL;
	}

	m_hIcon=createIcon(env,m_hWnd,color,mask,widths,widthd,height);
	if(m_hWnd && m_hIcon)
	{
		PostMessage(m_hWnd, WM_SETICON, 0, (LPARAM)m_hIcon);
		PostMessage(m_hWnd, WM_SETICON, 1, (LPARAM)m_hIcon);
	}
}

jobject CCursorIcon::createCursor( JNIEnv *env, jintArray color, jbyteArray mask, jint widths, jint widthd, jint height, jint x, jint y )
{
	if(widthd!=GetSystemMetrics(SM_CXCURSOR) || height!=GetSystemMetrics(SM_CYCURSOR))
		return NULL;

	HICON hIcon=createIcon(env,NULL,color,mask,widths,widthd,height,true,x,y);
	
	if(hIcon)
	{try{
		JCursor ret;ret.create(env,(jint)-1);
		ret.setnativeContext((jlong)hIcon);
		return ret;
	}catch(JNIPP::JException&)
	{}}

	return NULL;
}

void CCursorIcon::setCursor(JNIEnv*env, jobject o )
{
	try
	{
		JCursor cursor(env,o);
		HICON hIcon=(HICON)cursor.getnativeContext();
		if(hIcon==NULL)
			cursor.setnativeContext((jlong)GetSystemCursor(cursor.gettype()));

		if(m_hWnd)
			PostMessage(m_hWnd,MSG_SETCURSOR,0,(LPARAM)hIcon);
	}catch(JNIPP::JException&)
	{}	
}
HCURSOR CCursorIcon::GetSystemCursor(int t)
{
	LPTSTR v; 

	switch ( t )
	{
	case 1:
		v = IDC_CROSS;
		break;
	case 2:
		v = IDC_IBEAM;
		break;
	case 3:
		v = IDC_WAIT;
		break;
	case 4:
	case 7:
		v = IDC_SIZENESW;
		break;
	case 5:
	case 6:
		v = IDC_SIZENWSE;
		break;
	case 8:
	case 9:
		v = IDC_SIZENS;
		break;
	case 10:
	case 11:
		v = IDC_SIZEWE;
		break;
	case 12:
		v = IDC_HAND;
		break;
	case 13:
		v = IDC_SIZEALL;
		break;
	default:
		v = IDC_ARROW;
		break;
	}
	HCURSOR ret = LoadCursor(NULL,v);
	if ( ret=NULL )
		ret = LoadCursor(NULL,IDC_ARROW);
	return ret;
}

void CCursorIcon::setCursorVisible( BOOL e )
{
	POINT pos;
	GetCursorPos(&pos);
	ScreenToClient(m_hWnd, &pos);
	RECT rc;
	GetClientRect(m_hWnd, &rc);

	int ht=HTCLIENT;
	if ( rc.left > pos.x || rc.right < pos.x || rc.top > pos.y || rc.bottom < pos.y )
		ht = HTCAPTION;

	if(e && m_bCursorHide)
		m_bCursorHide=FALSE;
	else
	if(!e && !m_bCursorHide)
		m_bCursorHide=TRUE;

	PostMessage(m_hWnd,WM_SETCURSOR,0,(LPARAM)ht);
}

void CCursorIcon::onSetCursor( WORD hittest )
{
	if ( m_bCursorHideLast )
	{
		if ( !(m_bCursorHide && hittest == HTCLIENT ))
		{
			ShowCursor(TRUE);
			m_bCursorHideLast = FALSE;
		}
	}
	else
	{
		if ( m_bCursorHide && hittest == HTCLIENT )
		{
			ShowCursor(FALSE);
			m_bCursorHideLast = TRUE;
		}
	}

	if ( m_hCursor )
		SetCursor(m_hCursor);
}

void CCursorIcon::init( HWND hWnd )
{
	m_hWnd=hWnd;
	m_hCursor=LoadCursor (NULL, IDC_ARROW) ;
	if(m_hIcon)
	{
		SendMessage(hWnd,WM_SETICON,0,(LPARAM)m_hIcon);
		SendMessage(hWnd,WM_SETICON,1,(LPARAM)m_hIcon);
	}
}

void CCursorIcon::release()
{
	m_hCursor = NULL;
}

void CCursorIcon::onShowCursor( BOOL e )
{
	m_bCursorHide=(e==FALSE);
}

//////////////////////////////////////////////////////////////////////////
JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_setIconImageFromIntRasterData
(JNIEnv *env, jobject, jintArray color, jbyteArray mask, jint widths, jint widthd, jint height)
{
	g_cursorIcon.setIconImageFromIntRasterData(env,color,mask,widths,widthd,height);
}

JNIEXPORT jobject JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_createCursorNative
(JNIEnv *env, jobject, jintArray color, jbyteArray mask, jint widths, jint widthd, jint height, jint x, jint y)
{
	return g_cursorIcon.createCursor(env,color,mask,widths,widthd,height,x,y);
}

JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_setCursorNative
(JNIEnv *env, jobject, jobject o)
{
	g_cursorIcon.setCursor(env,o);
}

JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_setCursorVisibleNative
(JNIEnv *, jobject, jboolean e)
{
	g_cursorIcon.setCursorVisible(e);
}
